#include "GY_PolarActiveArea.h"
#include <QDebug>
#include <QCursor>
#include <QPainter>
#include <QtMath>

GY_PolarActiveArea::GY_PolarActiveArea(const QString &guid, QGraphicsItem *parent)
    :GY_BasicsGraphicsObject(guid,this,parent)
{
    //图元类型
    GY_Object::setUserData(GY_ENUM::ClassType,QVariant("RectActiveArea"));
    initializationPropertyInfo();
    //鼠标样式
    setCursor(QCursor(Qt::CrossCursor));
    setAcceptHoverEvents(true);
    setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsFocusable);
    QPen pen;
    pen.setColor(Qt::red);
    pen.setStyle(Qt::DotLine);
    this->setPen(pen);
    updateDraw();
    QMap<QVariant,QPointF> editPoints = {
        {"RadiusPoint1",m_PropertyInfoMap["RadiusPoint1"].propertyValue.toPointF()},
        {"RadiusPoint2",m_PropertyInfoMap["RadiusPoint2"].propertyValue.toPointF()}
    };
    this->setEditPointF(editPoints);
    this->setCenterPointF(m_PropertyInfoMap["Center"].propertyValue.toPointF());
}

void GY_PolarActiveArea::initializationPropertyInfo()
{
    //名称
    GY_PropertyInfo ObjectName(this);
    ObjectName.propertyName = "ObjectName";
    ObjectName.propertyValue = QString();
    ObjectName.updateType = Update|OrdinaryAttributes;
    ObjectName.propertyType = QStringPropertyType;
    ObjectName.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateObjectName;
    m_PropertyInfoMap.insert("ObjectName",ObjectName);
    m_PropertyInfoMap[ObjectName.propertyName].setConnect();

    //可见
    GY_PropertyInfo IsVisible(this);
    IsVisible.propertyName = "IsVisible";
    IsVisible.propertyValue = true;
    IsVisible.updateType = Update|OrdinaryAttributes;
    IsVisible.propertyType = BoolPropertyType;
    IsVisible.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateIsVisible;
    m_PropertyInfoMap.insert("IsVisible",IsVisible);
    m_PropertyInfoMap[IsVisible.propertyName].setConnect();

    //位置
    GY_PropertyInfo positonPropertyInfo(this);
    positonPropertyInfo.propertyName="Center";
    positonPropertyInfo.propertyValue=QPointF(0,0);
    positonPropertyInfo.updateType = Update|MoveUpdate|PointOfRelative;
    positonPropertyInfo.propertyType = PointPropertyType;
    positonPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateCirlePoint;
    m_PropertyInfoMap.insert(positonPropertyInfo.propertyName,positonPropertyInfo);
    m_PropertyInfoMap[positonPropertyInfo.propertyName].setConnect();

    //开始角度
    GY_PropertyInfo startAnglePropertyInfo(this);
    startAnglePropertyInfo.propertyName="ReferenceAngle";
    startAnglePropertyInfo.propertyValue=0.0;
    startAnglePropertyInfo.updateType = Update|OrdinaryAttributes;
    startAnglePropertyInfo.propertyType = DoublePropertyType;
    startAnglePropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateStartAngle;
    m_PropertyInfoMap.insert(startAnglePropertyInfo.propertyName,startAnglePropertyInfo);
    m_PropertyInfoMap[startAnglePropertyInfo.propertyName].setConnect();

    //经过角度
    GY_PropertyInfo SweptAnglePropertyInfo(this);
    SweptAnglePropertyInfo.propertyName="SweptAngle";
    SweptAnglePropertyInfo.propertyValue=90.0;
    SweptAnglePropertyInfo.updateType = Update|OrdinaryAttributes;
    SweptAnglePropertyInfo.propertyType = DoublePropertyType;
    SweptAnglePropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateSweptAngele;
    m_PropertyInfoMap.insert(SweptAnglePropertyInfo.propertyName,SweptAnglePropertyInfo);
    m_PropertyInfoMap[SweptAnglePropertyInfo.propertyName].setConnect();

    //半径
    GY_PropertyInfo RadiusPropertyInfo(this);
    RadiusPropertyInfo.propertyName="Radius";
    RadiusPropertyInfo.propertyValue=100.0;
    RadiusPropertyInfo.updateType = Update|OrdinaryAttributes;
    RadiusPropertyInfo.propertyType = DoublePropertyType;
    RadiusPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateRadius;
    m_PropertyInfoMap.insert(RadiusPropertyInfo.propertyName,RadiusPropertyInfo);
    m_PropertyInfoMap[RadiusPropertyInfo.propertyName].setConnect();

    //半径点1
    GY_PropertyInfo RadiusPoint1PropertyInfo(this);
    RadiusPoint1PropertyInfo.propertyName="RadiusPoint1";
    RadiusPoint1PropertyInfo.propertyValue=QPointF(100,0);
    RadiusPoint1PropertyInfo.propertyType = PointPropertyType;
    RadiusPoint1PropertyInfo.updateType = NotUpdate;
    RadiusPoint1PropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateRadiusPoint1;
    m_PropertyInfoMap.insert(RadiusPoint1PropertyInfo.propertyName,RadiusPoint1PropertyInfo);
    m_PropertyInfoMap[RadiusPoint1PropertyInfo.propertyName].setConnect();

    //半径点2
    GY_PropertyInfo RadiusPoint2PropertyInfo(this);
    RadiusPoint2PropertyInfo.propertyName="RadiusPoint2";
    RadiusPoint2PropertyInfo.propertyValue=QPointF(-120,0);
    RadiusPoint2PropertyInfo.updateType = NotUpdate;
    RadiusPoint2PropertyInfo.propertyType = PointPropertyType;
    RadiusPoint2PropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateRadiusPoint2;
    m_PropertyInfoMap.insert(RadiusPoint2PropertyInfo.propertyName,RadiusPoint2PropertyInfo);
    m_PropertyInfoMap[RadiusPoint2PropertyInfo.propertyName].setConnect();

    //是否过圆心
    GY_PropertyInfo IncludeCenterPropertyInfo(this);
    IncludeCenterPropertyInfo.propertyName="IncludeCenter";
    IncludeCenterPropertyInfo.propertyValue=true;
    IncludeCenterPropertyInfo.updateType = Update|OrdinaryAttributes;
    IncludeCenterPropertyInfo.propertyType = BoolPropertyType;
    IncludeCenterPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateIncludeCenter;
    m_PropertyInfoMap.insert(IncludeCenterPropertyInfo.propertyName,IncludeCenterPropertyInfo);
    m_PropertyInfoMap[IncludeCenterPropertyInfo.propertyName].setConnect();

    GY_PropertyInfo EnablePropertyInfo(this);
    EnablePropertyInfo.propertyName="Enable";
    EnablePropertyInfo.propertyValue=true;
    EnablePropertyInfo.updateType = Update|OrdinaryAttributes;
    EnablePropertyInfo.propertyType = BoolPropertyType;
    EnablePropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateEnable;
    m_PropertyInfoMap.insert(EnablePropertyInfo.propertyName,EnablePropertyInfo);
    m_PropertyInfoMap[EnablePropertyInfo.propertyName].setConnect();

    GY_PropertyInfo EnableSingleTouchPropertyInfo(this);
    EnableSingleTouchPropertyInfo.propertyName="EnableSingleTouch";
    EnableSingleTouchPropertyInfo.propertyValue=true;
    EnableSingleTouchPropertyInfo.updateType = Update|OrdinaryAttributes;
    EnableSingleTouchPropertyInfo.propertyType = BoolPropertyType;
    EnableSingleTouchPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateEnableSingleTouch;
    m_PropertyInfoMap.insert(EnableSingleTouchPropertyInfo.propertyName,EnableSingleTouchPropertyInfo);
    m_PropertyInfoMap[EnableSingleTouchPropertyInfo.propertyName].setConnect();

    GY_PropertyInfo RelativeMotionPropertyInfo(this);
    RelativeMotionPropertyInfo.propertyName="RelativeMotion";
    RelativeMotionPropertyInfo.propertyValue=false;
    RelativeMotionPropertyInfo.updateType = Update|OrdinaryAttributes;
    RelativeMotionPropertyInfo.propertyType = BoolPropertyType;
    RelativeMotionPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateRelativeMotion;
    m_PropertyInfoMap.insert(RelativeMotionPropertyInfo.propertyName,RelativeMotionPropertyInfo);
    m_PropertyInfoMap[RelativeMotionPropertyInfo.propertyName].setConnect();

    GY_PropertyInfo CaptureDragPropertyInfo(this);
    CaptureDragPropertyInfo.propertyName="CaptureDrag";
    CaptureDragPropertyInfo.propertyValue=true;
    CaptureDragPropertyInfo.updateType = Update|OrdinaryAttributes;
    CaptureDragPropertyInfo.propertyType = BoolPropertyType;
    CaptureDragPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateCaptureDrag;
    m_PropertyInfoMap.insert(CaptureDragPropertyInfo.propertyName,CaptureDragPropertyInfo);
    m_PropertyInfoMap[CaptureDragPropertyInfo.propertyName].setConnect();

    GY_PropertyInfo CursorReprPropertyInfo(this);
    CursorReprPropertyInfo.propertyName="CursorRepr";
    CursorReprPropertyInfo.propertyValue="Default";
    CursorReprPropertyInfo.updateType = Update|OrdinaryAttributes;
    CursorReprPropertyInfo.propertyType = QStringPropertyType;
    CursorReprPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_PolarActiveArea::updateCursorRepr;
    m_PropertyInfoMap.insert(CursorReprPropertyInfo.propertyName,CursorReprPropertyInfo);
    m_PropertyInfoMap[CursorReprPropertyInfo.propertyName].setConnect();
}

void GY_PolarActiveArea::updateDraw()
{
    QPointF centerPoint= m_PropertyInfoMap.value("Center").propertyValue.toPointF();
    qreal startAngle=m_PropertyInfoMap.value("ReferenceAngle").propertyValue.toDouble();
    qreal sweptAngle=m_PropertyInfoMap.value("SweptAngle").propertyValue.toDouble();
    qreal Radius=m_PropertyInfoMap.value("Radius").propertyValue.toDouble();
    QPointF innerDiffPoint=QPointF(centerPoint.x()-Radius,centerPoint.y()-Radius);
    QPainterPath Path;
    if(m_PropertyInfoMap["IncludeCenter"].propertyValue.toBool()) {
        Path.moveTo(centerPoint);
        Path.arcTo(innerDiffPoint.x(),innerDiffPoint.y(),2*Radius,2*Radius,-startAngle,-((sweptAngle)<0?(360+(sweptAngle)):(sweptAngle)));
        Path.closeSubpath();
        this->setPath(Path);
    }else {
        Path.arcMoveTo(innerDiffPoint.x(),innerDiffPoint.y(),2*Radius,2*Radius,-startAngle);
        Path.arcTo(innerDiffPoint.x(),innerDiffPoint.y(),2*Radius,2*Radius,-startAngle,-((sweptAngle)<0?(360+(sweptAngle)):(sweptAngle)));
        Path.closeSubpath();
        this->setPath(Path);
    }
}

bool GY_PolarActiveArea::updateCirlePoint(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue=this->mapFromScene(value.toPointF());
    this->setCenterPointF(this->mapFromScene(value.toPointF()));
    calculateRadiusPoint2Position();
    calculateRadiusPoint1Position();
    updateDraw();
    return true;
}

bool GY_PolarActiveArea::updateStartAngle(const QString &name, const QVariant &value)
{
    if(!value.canConvert<double>())
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue=value.toDouble();
    updateDraw();
    calculateRadiusPoint2Position();
    calculateRadiusPoint1Position();
    return true;
}

bool GY_PolarActiveArea::updateSweptAngele(const QString &name, const QVariant &value)
{
    if(!value.canConvert<double>())
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue=value.toDouble();
    updateDraw();
    calculateRadiusPoint1Position();
    return true;
}

bool GY_PolarActiveArea::updateRadius(const QString &name, const QVariant &value)
{
    if(!value.canConvert<double>())
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue=value.toDouble();
    updateDraw();
    calculateRadiusPoint2Position();
    calculateRadiusPoint1Position();
    return true;
}

bool GY_PolarActiveArea::updateRadiusPoint2(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF point=this->mapFromScene(value.toPointF());
    //基于圆心的偏移坐标
    QPointF diffPoint=point-m_PropertyInfoMap.value("Center").propertyValue.toPointF();
    qreal pointRadius=qSqrt(qPow(qAbs(diffPoint.x()),2)+qPow(qAbs(diffPoint.y()),2));
    m_PropertyInfoMap["Radius"].propertyValue=pointRadius;
    qreal pointAngle=precalculatedAngle(m_PropertyInfoMap.value("Center").propertyValue.toPointF(),point);
    m_PropertyInfoMap["ReferenceAngle"].propertyValue=pointAngle;
    calculateRadiusPoint1Position();
    updateDraw();
    m_PropertyInfoMap[name].propertyValue=point;
    this->setEditPointF(name,point);
    return true;
}

bool GY_PolarActiveArea::updateRadiusPoint1(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF point=this->mapFromScene(value.toPointF());
    //基于圆心的偏移坐标
    qreal pointAngle=precalculatedAngle(m_PropertyInfoMap.value("Center").propertyValue.toPointF(),point);
    m_PropertyInfoMap["SweptAngle"].propertyValue=pointAngle-m_PropertyInfoMap["ReferenceAngle"].propertyValue.toDouble();
    calculateRadiusPoint2Position();
    QPointF  Point1=precalculatedPosition(m_PropertyInfoMap["Center"].propertyValue.toPointF(),m_PropertyInfoMap["Radius"].propertyValue.toDouble(),m_PropertyInfoMap["SweptAngle"].propertyValue.toDouble()+m_PropertyInfoMap["ReferenceAngle"].propertyValue.toDouble());
    updateDraw();
    m_PropertyInfoMap[name].propertyValue=Point1;
    this->setEditPointF(name,Point1);
    return true;
}

bool GY_PolarActiveArea::updateIncludeCenter(const QString &name, const QVariant &value)
{
    if(!value.canConvert<bool>()) {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue = value.toBool();
    updateDraw();
    return true;
}

bool GY_PolarActiveArea::updateEnable(const QString &name, const QVariant &value)
{
    if(!value.canConvert<bool>()) {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue = value.toBool();
    updateDraw();
    return true;
}

bool GY_PolarActiveArea::updateEnableSingleTouch(const QString &name, const QVariant &value)
{
    if(!value.canConvert<bool>()) {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue = value.toBool();
    updateDraw();
    return true;
}

bool GY_PolarActiveArea::updateRelativeMotion(const QString &name, const QVariant &value)
{
    if(!value.canConvert<bool>()) {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue = value.toBool();
    updateDraw();
    return true;
}

bool GY_PolarActiveArea::updateCaptureDrag(const QString &name, const QVariant &value)
{
    if(!value.canConvert<bool>()) {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue = value.toBool();
    updateDraw();
    return true;
}

bool GY_PolarActiveArea::updateCursorRepr(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QString>()) {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue = value.toString();
    updateDraw();
    return true;
}

void GY_PolarActiveArea::calculateRadiusPoint2Position()
{
    QPointF RadiusPoint2=precalculatedPosition(m_PropertyInfoMap["Center"].propertyValue.toPointF(),m_PropertyInfoMap["Radius"].propertyValue.toDouble(),m_PropertyInfoMap["ReferenceAngle"].propertyValue.toDouble());
    m_PropertyInfoMap["RadiusPoint2"].propertyValue=RadiusPoint2;
    this->setEditPointF("RadiusPoint2",RadiusPoint2);
}

void GY_PolarActiveArea::calculateRadiusPoint1Position()
{
    QPointF RadiusPoint1=precalculatedPosition(m_PropertyInfoMap["Center"].propertyValue.toPointF(),m_PropertyInfoMap["Radius"].propertyValue.toDouble(),m_PropertyInfoMap["SweptAngle"].propertyValue.toDouble()+m_PropertyInfoMap["ReferenceAngle"].propertyValue.toDouble());
    m_PropertyInfoMap["RadiusPoint1"].propertyValue=RadiusPoint1;
    this->setEditPointF("RadiusPoint1",RadiusPoint1);
}

QPointF GY_PolarActiveArea::precalculatedPosition(const QPointF &centerPoint, const double radius, const double angele)
{
    qreal radian=qDegreesToRadians(angele); //弧度
    QPointF resultPoint;
    resultPoint.setX(cos(radian)*radius);
    resultPoint.setY(sin(radian)*radius);
    resultPoint+=centerPoint;
    return resultPoint;
}

qreal GY_PolarActiveArea::precalculatedAngle(const QPointF &centerPoint, const QPointF &calculatePoint)
{
    //基于圆心的偏移坐标
    QPointF diffPoint=calculatePoint-centerPoint;
    qreal pointAngle=qRadiansToDegrees(qAtan2(diffPoint.y(),diffPoint.x()));
    if(diffPoint.y()<0)
    {
        pointAngle+=360;
    }
    return pointAngle;
}
